package service

import (
	"fmt"
	"log"
	"ssr/common"
	"ssr/dto"
	"ssr/models"
	"ssr/utils"
	"strconv"
	"time"

	"golang.org/x/exp/rand"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type JackpotService struct {
	db *gorm.DB
}

func NewJackpotService() *JackpotService {
	return &JackpotService{
		db: common.GetDB(),
	}
}

func (s *JackpotService) GetJackpotUserInfo(userId string) (*models.GameUser, error) {
	var user models.GameUser
	if err := s.db.Where("id = ?", userId).
		Select("id", "username", "nickname", "email", "phone", "created_at", "state", "balance").
		Preload("Bets").First(&user).Error; err != nil {
		return nil, err
	}
	return &user, nil
}

func (s *JackpotService) GetJackpotUserList(queryParams dto.CommonQuery) (*common.Pagination[models.GameUser], error) {

	var userList []models.GameUser
	var total int64
	searchKey := "%" + string(queryParams.Keyword) + "%"
	querySql := `username LIKE ? OR email LIKE ? OR phone LIKE ?`
	if err := s.db.Preload("Bets").Model(&models.GameUser{}).
		Where(querySql, searchKey, searchKey, searchKey).
		Count(&total).Error; err != nil {
		return nil, err
	}
	limit := queryParams.Limit
	offset := (queryParams.Page - 1) * limit
	if err := s.db.Model(&models.GameUser{}).Where(querySql, searchKey, searchKey, searchKey).
		Limit(limit).
		Offset(offset).
		Order("created_at DESC").
		Find(&userList).Error; err != nil {
		return nil, err
	}
	result := common.NewPagination(queryParams.Page, queryParams.Limit, total, userList)
	return result, nil
}

func (s *JackpotService) DisposeJackpotUser(user dto.JackpotUserRegisterDTO) (string, error) {
	if user.UserId != "" {
		if err := s.db.Where("id = ?", user.UserId).Updates(&models.GameUser{
			Password: user.Password,
			Email:    user.Email,
			Phone:    user.Phone,
			Nickname: user.Nickname,
		}).Error; err != nil {
			return "更新失败", err
		}
		return "更新成功", nil
	}

	if user.Nickname == "" {
		// 拿到随机时间戳 生成昵称
		now := time.Now().Unix()
		user.Nickname = "用户_" + strconv.FormatInt(now, 10)
	}
	if err := s.db.Create(&models.GameUser{
		Username: user.Username,
		Password: user.Password,
		Email:    user.Email,
		Phone:    user.Phone,
		Nickname: user.Nickname,
	}).Error; err != nil {
		log.Println(err)
		return "添加失败", err
	}

	return "添加成功", nil
}

func (s *JackpotService) DeleteJackpotUser(userId string) (string, error) {
	if err := s.db.Where("id = ?", userId).
		Delete(&models.GameUser{}).Error; err != nil {
		return "删除失败", err
	}
	return "删除成功", nil
}

func (s *JackpotService) GetGameResultList(queryParams dto.CommonQuery) (*common.Pagination[*models.GameResult], error) {
	var resultList []*models.GameResult
	var total int64
	serachKey := "%" + string(queryParams.Keyword) + "%"
	querySql := `game_code LIKE ?`
	if err := s.db.Model(&models.GameResult{}).
		Where(querySql, serachKey).
		Count(&total).Error; err != nil {
		return nil, err
	}
	limit := queryParams.Limit
	offset := (queryParams.Page - 1) * limit
	if err := s.db.Preload("Bets").Model(&models.GameResult{}).
		Where(querySql, serachKey).
		Limit(limit).
		Offset(offset).
		Order("created_at DESC").
		Find(&resultList).Error; err != nil {
		return nil, err
	}
	// 未开奖看着不到结果 内定结果 隐藏
	for _, v := range resultList {
		if v.Status == 0 {
			v.Dice1 = 0
			v.Dice2 = 0
			v.Dice3 = 0
			v.Sum = 0
		}
	}
	result := common.NewPagination(queryParams.Page, queryParams.Limit, total, resultList)
	return result, nil
}

func (s *JackpotService) AddGameResult(result dto.GameResultDTO) (string, error) {
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()
	// 随机筛子点数
	if result.IsRandom {
		result.Dice1 = rand.Intn(6) + 1
		result.Dice2 = rand.Intn(6) + 1
		result.Dice3 = rand.Intn(6) + 1
	}
	// 期号生成
	gameCode := time.Now().Format("20060102150405")
	// 暂定5分钟后开奖
	var gameResult models.GameResult
	resultTime := time.Now().Add(time.Minute * 5)
	if err := tx.Create(&models.GameResult{
		GameCode:   gameCode,
		Dice1:      result.Dice1,
		Dice2:      result.Dice2,
		Dice3:      result.Dice3,
		Sum:        result.Dice1 + result.Dice2 + result.Dice3,
		ResultTime: resultTime,
	}).Scan(&gameResult).Error; err != nil {
		tx.Rollback()
		return "添加失败", err
	}
	// 新增奖池
	if err := tx.Create(&models.JackPotPoll{
		GameResultId: gameResult.ID,
		GameCode:     gameResult.GameCode,
		TotalAmount:  1000, // 初始金额
		OddsValue:    0,
	}).Error; err != nil {
		tx.Rollback()
		return "添加失败", err
	}
	// 开启定时器 5分钟后开奖
	go func() {
		time.Sleep(time.Minute * 5)
		s.OpenGameResult(dto.OpenGameResultParamsDTO{
			GameResultId: gameResult.ID,
		})
	}()
	tx.Commit()

	return "添加成功", nil
}

func (s *JackpotService) Recharge(result dto.RechargeParamsDTO) (string, error) {
	if err := s.db.Model(&models.GameUser{}).
		Where("id = ?", result.UserId).
		Update("balance", gorm.Expr("balance + ?", result.Amount)).
		Error; err != nil {
		return "充值失败", err
	}
	return "充值成功", nil
}

func (s *JackpotService) OpenGameResult(result dto.OpenGameResultParamsDTO) (string, error) {
	// 开启事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()
	var gameResult models.GameResult
	if err := tx.Model(&models.GameResult{}).Preload("Bets").
		Where("id = ?", result.GameResultId).
		First(&gameResult).Error; err != nil {
		return "获取游戏本期信息失败", err
	}
	if gameResult.Status == 1 {
		return "本期已经开奖", nil
	}
	for _, v := range gameResult.Bets {
		betModel, err := utils.JudgeBet(&gameResult, v)
		if err != nil {
			tx.Rollback()
			return "开奖失败", err
		}
		if err := tx.Where("id = ?", v.ID).
			Updates(&betModel).Error; err != nil {
			tx.Rollback()
			return "开奖失败", err
		}
		log.Printf("betModel: %#v\n", betModel)
		if betModel.IsWin {
			var jackpotPoll models.JackPotPoll
			if err := tx.Where("game_result_id = ?", gameResult.ID).
				First(&jackpotPoll).Error; err != nil {
				tx.Rollback()
				return "开奖失败", err
			}
			jackpotPoll.TotalAmount -= betModel.WinAmount
			if err := tx.Model(&models.JackPotPoll{}).Where("game_result_id = ?", gameResult.ID).
				Updates(&jackpotPoll).Error; err != nil {
				tx.Rollback()
				return "开奖失败", err
			}
			// 增加用户余额
			if err := tx.Model(&models.GameUser{}).Where("id = ?", betModel.GameUserId).
				Update("balance", gorm.Expr("balance + ?", betModel.WinAmount)).
				Error; err != nil {
				tx.Rollback()
				return "开奖失败", err
			}
		}
	}

	if err := tx.Model(&models.GameResult{}).Where("id = ?", gameResult.ID).
		Update("status", 1).Error; err != nil {
		tx.Rollback()
		return "开奖失败", err
	}
	// 事务提交
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		return "开奖失败", err
	}
	return "开奖成功", nil
}

func (s *JackpotService) GetOddRuleList(queryParams dto.OddsQueryDTO) (*common.Pagination[*models.OddRules], error) {
	var ruleList []*models.OddRules
	var total int64
	serachKey := "%" + string(queryParams.Keyword) + "%"
	querySql := `(bet_type LIKE ? OR odds_value LIKE ?)`
	if queryParams.BetType != "" {
		querySql += " AND bet_type =" + queryParams.BetType
	}
	if queryParams.IsActive == 1 {
		querySql += " AND is_active = 1"
	}

	if err := s.db.Model(&models.OddRules{}).Where(querySql, serachKey, serachKey).
		Count(&total).Error; err != nil {
		return nil, err
	}
	limit := queryParams.Limit
	offset := (queryParams.Page - 1) * limit
	if err := s.db.Model(&models.OddRules{}).Where(querySql, serachKey, serachKey).Limit(limit).
		Offset(offset).Order("sort DESC").Find(&ruleList).Error; err != nil {
		return nil, err
	}
	result := common.NewPagination(queryParams.Page, queryParams.Limit, total, ruleList)
	return result, nil
}

func (s *JackpotService) DisposeOddRule(result dto.DisposeOddRuleParamsDTO) (string, error) {
	if result.RuleId != "" {
		fmt.Printf("ruleId: %#v\n", result)
		if err := s.db.Model(&models.OddRules{}).Where("id = ?", result.RuleId).Updates(map[string]interface{}{
			"BetType":   result.BetType,
			"OddsValue": result.OddsValue,
			"OddsName":  result.OddsName,
			"IsActive":  result.IsActive,
		}).Error; err != nil {
			return "修改失败", err
		}
		return "修改成功", nil
	}
	if err := s.db.Create(&models.OddRules{
		IsActive:  result.IsActive,
		BetType:   result.BetType,
		OddsValue: result.OddsValue,
		OddsName:  result.OddsName,
	}).Error; err != nil {
		return "添加失败", err
	}
	return "添加成功", nil
}

func (s *JackpotService) DeleteOddRule(ruleId string) (string, error) {
	if err := s.db.Delete(&models.OddRules{}, "id = ?", ruleId).Error; err != nil {
		return "删除失败", err
	}
	return "删除成功", nil
}

func (s *JackpotService) Bet(params dto.BetFormDTO) (string, error) {
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 1. 查询用户并加锁（避免并发修改余额）
	var user models.GameUser
	if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
		Where("id = ?", params.GameUserId).First(&user).Error; err != nil {
		tx.Rollback()
		return "查询用户失败", err
	}

	// 2. 查询游戏结果
	var gameResult models.GameResult
	if err := tx.Where("id = ?", params.GameResultId).First(&gameResult).Error; err != nil {
		tx.Rollback()
		return "查询游戏结果失败", err
	}
	if gameResult.Status != 0 {
		tx.Rollback()
		return "游戏结果已开奖，无法下注", nil
	}

	// 3. 检查余额
	if params.TotalAmount > user.Balance {
		tx.Rollback()
		return "余额不足", nil
	}

	// 4. 更新用户余额
	if err := tx.Model(&user).Update("balance", user.Balance-params.TotalAmount).Error; err != nil {
		tx.Rollback()
		return "下注失败", err
	}
	for _, v := range params.BetParams {
		betModel, err := utils.DisposeJackpotBet(&v)
		if err != nil {
			tx.Rollback()
			return "下注失败", err
		}
		betModel.GameUserId = params.GameUserId
		betModel.GameCode = gameResult.GameCode
		// 创建 Bet 记录 关联 GameResult 和 Bet
		if err := tx.Create(&betModel).Error; err != nil {
			tx.Rollback()
			return "下注失败", err
		}
		if err := tx.Table("bet_game_result").Create(map[string]interface{}{
			"bet_id":         betModel.ID,
			"game_result_id": gameResult.ID,
		}).Error; err != nil {
			tx.Rollback()
			return "下注失败", err
		}
	}
	// 同步奖池余额和游戏结果状态
	if err := tx.Model(&models.JackPotPoll{}).Where("game_result_id = ?", gameResult.ID).Update("total_amount", gorm.Expr("total_amount + ?", params.TotalAmount)).Error; err != nil {
		tx.Rollback()
		return "下注失败", err
	}
	// 6. 提交事务（所有操作完成后一次性提交）
	if err := tx.Commit().Error; err != nil {
		return "下注失败: 提交事务失败", err
	}

	return "下注成功", nil
}
